import {arrAsubB} from "../lib/util/ToolMethods.js";

class UndoItem {
  addPoints = []
  addTriangles = []
  addCutLines = []
  addPlane
  addCameraState = []
  addSlicedTriangles = []
  triangleToCutLines = new Map();
  constructor(undoSlice) {
    this.addPoints = undoSlice.addPoints.slice();
    this.addTriangles = undoSlice.addTriangles.slice();
    this.addCutLines = undoSlice.addCutLines.slice();
    this.addPlane = undoSlice.addPlane;
    this.addCameraState = undoSlice.addCameraState;
    this.addSlicedTriangles = undoSlice.addSlicedTriangles.slice();
    undoSlice.triangleToCutLines.forEach((value, key) => {
      this.triangleToCutLines.set(key, value);
    });
  }
}

export default class UndoSlice {
  /**
   * @type {UndoItem[]}
   */
  stackUndo = []
  /**
   * @type {UndoItem[]}
   */
  stackRedo = []

  addPoints = []
  addTriangles = []
  addCutLines = []
  addPlane
  addCameraState = []
  addSlicedTriangles = []
  triangleToCutLines = new Map();

  clearStack() {
    this._afterAddUndo();
    this.stackUndo.length = 0;
    this.stackRedo.length = 0;
  }
  _afterAddUndo() {
    this.addPoints.length = 0;
    this.addTriangles.length = 0;
    this.addCutLines.length = 0;
    this.addPlane = null;
    this.addCameraState = null;
    this.addSlicedTriangles.length = 0;
    this.triangleToCutLines.clear();
  }
  addTriangleToCutLines(tri, line) {
    const cutLineArr = this.triangleToCutLines.get(tri);
    if (cutLineArr) {
      cutLineArr.push(line);
    } else {
      this.triangleToCutLines.set(tri, [line]);
    }
  }
  addUndoStack() {
    this.stackRedo.length = 0;
    const item = new UndoItem(this);
    this.stackUndo.push(item);
    this._afterAddUndo();
  }

  /**
   * @param {ShapeExtract} shapeExtract
   */
  undo(shapeExtract) {
    const item = this.stackUndo.pop();
    if (!item) {
      return;
    }
    this.stackRedo.push(item);
    arrAsubB(shapeExtract.cutLinesRefined, item.addCutLines);
    shapeExtract.cutPlanes.pop();
    shapeExtract.cutPoints.pop();
    shapeExtract.cameraStates.pop();
    arrAsubB(shapeExtract.slicedTriangles, item.addSlicedTriangles);
    arrAsubB(shapeExtract.trianglesAll, item.addTriangles);
    item.triangleToCutLines.forEach((value, key, map) => {
      const arrB = map.get(key);
      const arrA = shapeExtract.triangleToCutLines.get(key);
      arrAsubB(arrA, arrB);
    })
  }

  /**
   * @param {ShapeExtract} shapeExtract
   */
  redo(shapeExtract) {
    const item = this.stackRedo.pop();
    if (!item) {
      return;
    }
    this.stackUndo.push(item);
    shapeExtract.cutLinesRefined.push(...item.addCutLines);
    shapeExtract.cutPlanes.push(item.addPlane);
    shapeExtract.cutPoints.push(...item.addPoints);
    shapeExtract.cameraStates.push(item.addCameraState);
    shapeExtract.slicedTriangles.push(...item.addSlicedTriangles);
    shapeExtract.trianglesAll.push(...item.addTriangles);
    item.triangleToCutLines.forEach((value, key, map) => {
      const arrB = map.get(key);
      const arrA = shapeExtract.triangleToCutLines.get(key);
      if (arrA) {
        arrA.push(...arrB);
      } else {
        shapeExtract.triangleToCutLines.set(key, arrB);
      }
    });
  }
}
